package com.iaiai.cobra.core.config.intercepter;

import com.iaiai.cobra.common.util.JsonUtil;
import com.iaiai.cobra.core.config.intercepter.req.RequestWrapper;
import com.iaiai.cobra.core.config.intercepter.req.ResponseWrapper;
import com.iaiai.cobra.core.util.IpUtil;
import com.iaiai.cobra.platform.other.ip.PconlineIpAddress;
import com.iaiai.cobra.platform.other.ip.bean.PconlineIpAddressResponse;
import com.iaiai.cobra.redis.RedisAdminCache;
import com.iaiai.cobra.redis.RedisOnlineCache;
import com.iaiai.cobra.redis.bean.CacheOnline;
import com.iaiai.cobra.repository.bean.LogRequest;
import com.iaiai.cobra.system.service.LogRequestService;
import com.iaiai.cobra.web.vo.OnlineVo;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import java.io.IOException;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Component
public class LogIntercepter implements HandlerInterceptor {

    private long startTime; //接口访问时间

    @Autowired
    private LogRequestService logRequestService;

    @Autowired
    public RedisOnlineCache redisOnlineCache;

    @Autowired
    public RedisAdminCache redisAdminCache;

    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) throws Exception {
        startTime = System.currentTimeMillis();

        //缓存
        cacheUser(request);

        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request,
                           HttpServletResponse response,
                           Object handler,
                           ModelAndView modelAndView) throws Exception {
        ResponseWrapper responseWrapper = new ResponseWrapper((HttpServletResponse)response);
//        log.debug("....{}",new String(responseWrapper.getContent(),request.getCharacterEncoding()));
    }

    @Override
    public void afterCompletion(HttpServletRequest request,
                                HttpServletResponse response,
                                Object handler,
                                Exception ex) throws Exception {
        long processorTime = System.currentTimeMillis() - startTime;

        String url = request.getRequestURL().toString();
        if(StringUtils.isNotEmpty(request.getQueryString())){
            url += "?" + request.getQueryString();
        }

        log.debug("------> 接口请求耗时(毫秒): {}s / {}",processorTime,url);

        LogRequest logRequest = new LogRequest();
        logRequest.setIpv4(IpUtil.getIpv4(request));
        logRequest.setIpv6(getIpv6(request));
        logRequest.setCreateTime(new Date());
        logRequest.setDuration(processorTime);
        logRequest.setMethod(request.getMethod());
        logRequest.setHeaders(getHeaderReturnString(request));
        logRequest.setUrl(request.getRequestURL().toString());
        logRequest.setUserAgent(request.getHeader("user-agent"));

        if(StringUtils.isNotEmpty(logRequest.getIpv4())){
            try {
                PconlineIpAddressResponse ipAddressResponse = PconlineIpAddress.queryIpv4Address(logRequest.getIpv4());
                if (ipAddressResponse != null) {
                    logRequest.setIpAddress(ipAddressResponse.getAddr());
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }

        //判断请求是否是上传的文档，如果上传文档则不记录内容
        String contentType = request.getHeader("content-type");
        if(contentType!=null&&contentType.toLowerCase().indexOf("multipart/form-data")<0) {
            logRequest.setBody(new RequestWrapper(request).getBody());
        }
        logRequestService.save(logRequest);
    }

    /**
     * 获取所有的头信息
     * @param request
     * @return
     */
    public final static String getHeaderReturnString(HttpServletRequest request){
        StringBuilder header = new StringBuilder();
        Enumeration keys = request.getHeaderNames();

        if(keys!=null) {
            while (keys.hasMoreElements()) {
                try {
                    Object key = keys.nextElement();
                    if (key == null) continue;

                    Enumeration<String> values = request.getHeaders(key.toString());
                    while (values.hasMoreElements()) {
                        Object val = values.nextElement();
                        if (val == null) continue;

                        header.append(String.format("%s:%s", new Object[]{key, val})).append("\r\n");
                    }
                }catch (Exception e){

                }
            }
        }

        return header.toString();
    }

    private String getIpv6(HttpServletRequest request) throws UnknownHostException {
        String remoteAddr = request.getHeader("X-FORWARDED-FOR");
        if (remoteAddr == null || "".equals(remoteAddr)) {
            remoteAddr = request.getRemoteAddr();
        }

        InetAddress inetAddress = InetAddress.getByName(remoteAddr);
        if(inetAddress instanceof Inet6Address){
            return remoteAddr;
        }

        return null;
    }

    private void cacheUser(HttpServletRequest request) throws Exception {
        String token = request.getHeader("token");
        if(StringUtils.isEmpty(token))return;

        CacheOnline cacheOnline = redisOnlineCache.getOnlineByToken(token);
        if(cacheOnline!=null) {
            cacheOnline.setUrl(request.getRequestURL().toString());
            redisOnlineCache.setOnline(cacheOnline);
            return;
        }

        OnlineVo onlineVo = getOnline(token);

        String ipv4 = IpUtil.getIpv4(request);
        String ipAddr = null;
        if(StringUtils.isNotEmpty(ipv4)){
            try {
                PconlineIpAddressResponse ipAddressResponse = PconlineIpAddress.queryIpv4Address(ipv4);
                if (ipAddressResponse != null) {
                    ipAddr = ipAddressResponse.getAddr();
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }

        redisOnlineCache.setOnline(token,onlineVo.getUser().getId(),onlineVo.getUser().getName(),ipv4,ipAddr,request.getRequestURL().toString());
    }

    //获取登录用户
    protected OnlineVo getOnline(String token) throws IOException {
        String json = redisAdminCache.getLogin(token);
        if(StringUtils.isEmpty(json))return null;

        return JsonUtil.getInstance().deserialize(json, OnlineVo.class);
    }

}
